/* Copyright 2008 Bas van den Berg
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <string>

#include "yaffut.h"
#include "myassert.h"
#include "TestActivity.h"
#include "TestEventServer.h"
#include "TestRoom.h"
#include "TestSession.h"

#include "Global.h"
#include "TaskQueue.h"
#include "MudExit.h"
#include "MudItem.h"
#include "MudObject.h"
#include "MudPlayer.h"
#include "Parser.h"
#include "ParserFactory.h"
#include "color.h"

using namespace std;
using namespace Chronos;


class ActivityTestPortal : public Portal {
public:
    ActivityTestPortal(Room& destRoom_) : destRoom(destRoom_) {}
	virtual void pass(MudPlayer& player) {
        Room* oldRoom = player.getRoom();
        ASSERT_NOT_NULL(oldRoom);

        oldRoom->removePlayer(player, "");
        destRoom.addPlayer(player, "");
    }
private:
    Room& destRoom;

    ActivityTestPortal(const ActivityTestPortal& rhs);
    ActivityTestPortal& operator=(const ActivityTestPortal&);
};


class ActivityTest {
public:
    ActivityTest()
        : taskqueue(0)
        , parser(*ParserFactory::create())
		, room("Room")
		, room2("Room2")
        , session1("player1")
        , session2("player2")
        , player1(session1.getPlayer())
        , player2(session2.getPlayer())
    {
        Global<TaskQueue>::set(&taskqueue);
		room.addPlayer(player1, "");
		room.addPlayer(player2, "");
        room.addObject(new MudExit("north", "", new ActivityTestPortal(room2)));
        room2.addObject(new MudExit("south", "", new ActivityTestPortal(room)));
        session1.clear();
        session2.clear();
        room.clear();
    }
    ~ActivityTest() {
        player1.getRoom()->removePlayer(player1);
        player2.getRoom()->removePlayer(player2);
        delete &parser;
    }
	void checkResult(TestSession& session, const char* input, const string& expected) {
		parser.parse(session, input);
		session.SESSION_CHECKWRITTEN(expected);
	}

    TaskQueue taskqueue;
    Parser& parser;
    TestRoom room;
    TestRoom room2;

    TestSession session1;
    TestSession session2;
    MudPlayer& player1;
    MudPlayer& player2;
};


TEST(ActivityTest, testMovementShouldCancelActivity) {
    bool cancelled = false;
    TestActivity* activity = new TestActivity(&cancelled);
    player1.setActivity(activity);

    ASSERT_FALSE(cancelled);
    checkResult(session1, "north", "Room2 ("ANSI_YELLOW"south"ANSI_NORMAL")\n");
    ASSERT_TRUE(cancelled);
}


TEST(ActivityTest, testStartingCombatShouldCancelActivity) {
    bool cancelled = false;
    TestActivity* activity = new TestActivity(&cancelled);
    player1.setActivity(activity);

    ASSERT_FALSE(cancelled);
    checkResult(session1, "attack player2", "");
    ASSERT_TRUE(cancelled);
}


TEST(ActivityTest, testAttackedShouldCancelActivity) {
    bool cancelled = false;
    TestActivity* activity = new TestActivity(&cancelled);
    player1.setActivity(activity);

    ASSERT_FALSE(cancelled);
    checkResult(session2, "attack player1", "");
    taskqueue.runNextTime();
    ASSERT_TRUE(cancelled);
}


TEST(ActivityTest, testActivityShouldNotStartInCombat) {
    checkResult(session1, "attack player2", "");
    ASSERT_TRUE(player1.isInCombat());
    checkResult(session1, "search", "You cannot search during combat.\n");
}


TEST(ActivityTest, testMovementShouldCancelTrade) {
    checkResult(session1, "trade with player2", "You start a trade with player2.\n");

    checkResult(session1, "north", "trade cancelled.\nRoom2 ("ANSI_YELLOW"south"ANSI_NORMAL")\n");
}


TEST(ActivityTest, testStartingCombatShouldCancelTrade) {
    checkResult(session1, "trade with player2", "You start a trade with player2.\n");

    checkResult(session1, "attack player2", "trade cancelled.\n");
}


TEST(ActivityTest, testAttackedShouldCancelTrade) {
    checkResult(session1, "trade with player2", "You start a trade with player2.\n");
    session2.clear();

    checkResult(session2, "attack player1", "trade cancelled.\n");
    session1.SESSION_CHECKWRITTEN("trade cancelled.\n");
}


TEST(ActivityTest, testTradeShouldNotStartInCombat) {
    checkResult(session1, "attack player2", "");
    ASSERT_TRUE(player1.isInCombat());
    checkResult(session1, "trade with player2", "You cannot trade during combat.\n");
}


